﻿using System;
using System.Collections.Generic;
using System.Drawing;

namespace MonoPhysics
{
    /// <summary>
    /// Structure comportant tous les éléments physiques et dynamiques d'un objet.
    /// </summary>
    public struct PhysicContext
    {
        private List<Edge> cp;
        private bool ignoreGravity;
        private bool ignoleExternalColluding;
        private bool receiveColludeOnly;
        private bool ignoreTranslation;
        private bool ignoreRotation;
        private Vector vitesse;
        private Force persistantForce;
        private Vector lastStablePosDim;
        private List<Force> forces;
        private List<Force> extraForces;
        private float angularVitess;
        private float maxVitessX;
        private float maxVitessY;
        private float minVitessY;

        /// <summary>
        /// Crée un contexte physique personalisé.
        /// </summary>
        /// <param name="v">Vitesse initiale.</param>
        /// <param name="a">Accélération initiale.</param>
        public PhysicContext(Vector v, List<Force> a, bool ignGravity, bool ignExtCollude, bool ignRot, bool ignTrans, bool recvColludeOnly, Vector lastStablePD, Force pf, float angV,float maxVX,float maxVY,float minVY)
        {
            vitesse = v;
            if (a != null)
                forces = a;
            else
                forces = new List<Force>();
            this.cp = new List<Edge>();
            this.extraForces = new List<Force>();
            this.lastStablePosDim = lastStablePD;
            this.receiveColludeOnly = recvColludeOnly;
            this.ignoreGravity = ignGravity;
            this.ignoleExternalColluding = ignExtCollude;
            this.persistantForce = pf;
            this.angularVitess = angV;
            this.ignoreRotation = ignRot;
            this.ignoreTranslation = ignTrans;
            this.maxVitessX = maxVX;
            this.maxVitessY = maxVY;
            this.minVitessY = minVY;
        }

        public float MaxVitessX
        {
            get { return maxVitessX; }
            set { maxVitessX = value; }
        }
        public float MaxVitessY
        {
            get { return maxVitessY; }
            set { maxVitessY = value; }
        }
        public float MinVitessY
        {
            get { return minVitessY; }
            set { minVitessY = value; }
        }
        public float AngularVitess
        {
            get { return this.angularVitess; }
            set { angularVitess = value; }
        }

        public Force PersistantForce
        {
            get { return persistantForce; }
            set { persistantForce = value; }
        }
        /// <summary>
        /// Derniere position stable connue par l'objet (pour eviter les "teleportations"!)
        /// </summary>
        public Vector LastStablePosDim
        {
            get { return this.lastStablePosDim; }
            set { this.lastStablePosDim = value; }
        }
        /// <summary>
        /// Ensemble des objets avec lesquels on est entre en collisions.
        /// </summary>
        public List<Edge> CollisionCouples
        { get { return this.cp; } }
        /// <summary>
        /// Iniquel que l'ojet est (true) ou non (false) sensible a la gravite.
        /// </summary>
        public bool IgnoreGravity
        {
            get { return ignoreGravity; }
            set { ignoreGravity = value; }
        }

        public bool IgnoreRotation
        { get { return this.ignoreRotation; } }
        public bool IgnoreTranslation
        { get { return this.ignoreTranslation; } }
        /// <summary>
        /// Deux objet ayant ce flag a true n'entreront jamais en collision.
        /// </summary>
        public bool IgnoreExternalColluding
        { get { return ignoleExternalColluding; } }
        /// <summary>
        /// Indique que l'objet ne peu que recevoir des colisions mais pas en produire.
        /// </summary>
        public bool ReceiveColludeOnly
        { get { return receiveColludeOnly; } }
        /// <summary>
        /// Vitesse en m/sec.
        /// </summary>
        public Vector V
        {
            get { return vitesse; }
            set { vitesse = value; }
        }

        /// <summary>
        /// Accélération en m/sec2
        /// </summary>
        public List<Force> Forces
        {
            get { return forces; }
            set { forces = value; }
        }

        public List<Force> ExtraForces
        {
            get { return this.extraForces; }
            set { this.extraForces = value; }
        }
    }


    public struct Collision
    {
        public enum CollisionType { PointPoint, PointArrete };
        public Vector collisionNormal;
        public Vector relativeVelocity;
        public Vector arreteColuded; // arete avec laquelle on est entree en collision. Egal a arreteDroite si colision avec un point.
        public Vector arreteDroite;
        public Vector arreteGauche;
        public PointD collisionPoint;
        public Vector RessorPenetration;
        public CollisionType collisionType;
    }

    public static class Extender
    {
        public static Vector cross(this Vector v, Vector v2)
        {
            return new Vector((v.Y * v2.Z - v.Z * v2.Y), (v.Z * v2.X - v.X * v2.Z), (v.X * v2.Y - v.Y * v2.X));
        }
    }

    public struct Force
    {
        public Vector force;
        public Vector location;

        public Force(Vector force, Vector location)
        {
            this.force = force;
            this.location = location;
        }
    }
    public class EndPoint
    {
        public BroadBox own;
        public float value;
        public bool isMin;
    }

    public class BroadBox
    {
        public RigidBody own;
        public EndPoint[] min;
        public EndPoint[] max;
    }
}
